﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;

namespace CloudReader.Net.Server
{
    /// <summary>
    /// 服务器组件
    /// </summary>
    /// 


    public class CloudReaderServer : CloudReaderSocket
    {
        /// <summary>
        /// 初始化服务器组件
        /// </summary>
        /// 

        public static int ServerPort = 60200;

        int m_maxConnect;
        Semaphore m_operate;
        int m_connected;
        public ConnectionPool m_Pool { get; set; }
        Stack<Connection> m_avaliable;
        bool isRun;

        public bool isServerAlive { get => isRun; }
        public int Connections { get => m_connected; }
        public int MaxConnection { get => m_maxConnect; }
        public int AvaliableCount { get => m_avaliable.Count; }
        public IPEndPoint Server { get => m_socket.LocalEndPoint as IPEndPoint; }

        public CloudReaderServer() : base()
        {
#if DEBUG
            SetDefault(ServerPort);
#else
            SetDefault(ServerPort);
#endif
            Init();

        }

        void Init()
        {
            m_Pool = new ConnectionPool();
            m_avaliable = new Stack<Connection>();
        }



#region 公开字段

        /// <summary>
        /// 启动服务器，并做初始化工作
        /// </summary>
        /// <param name="maxConnect"></param>
        public void Start(int maxConnect)
        {

            isRun = true;
            m_maxConnect = maxConnect;
            m_socket.Listen(maxConnect);
            m_operate = new Semaphore(m_maxConnect, m_maxConnect);
            for (int i = 0; i < maxConnect; i++)
            {
                var c = new Connection();
                c.OnReceiveCompleted += new Action<SocketAsyncEventArgs, Protocol.CloudReaderPackage>(ClientRequest);
                m_avaliable.Push(c);
            }
            StartAccept(null);
        }

        public void Stop()
        {
            try
            {
                m_socket.Close();
                m_socket.Dispose();
            }
            catch
            {

            }
            finally
            {

            }
        }

        public void Dispose()
        {
            Stop();
            GC.SuppressFinalize(this);
        }
        public event Action<SocketAsyncEventArgs> OnNewConnection;
        public event Action<SocketAsyncEventArgs, Protocol.CloudReaderPackage> OnNewPackageReceive;
        public event Action<Exception> OnNewExceptionRaised;
        public event Action<Connection> OnConnectionClose;

#endregion

#region 固定部分
        // 以下函数已经固定，不允许修改
        protected void StartAccept(SocketAsyncEventArgs e)
        {
            if (e == null)
            {
                e = new SocketAsyncEventArgs();
                e.Completed += new EventHandler<SocketAsyncEventArgs>(AcceptCompleted);
            }
            else
            {
                e.AcceptSocket = null;
            }
            m_operate.WaitOne();
            //异步接收请求
            if (!m_socket.AcceptAsync(e))
            {
                ProcessAccept(e);
            }
        }
        protected void AcceptCompleted(object sender, SocketAsyncEventArgs e)
        {
            ProcessAccept(e);
        }
        protected void ProcessAccept(SocketAsyncEventArgs e)
        {
            //处理Accept事件
            if (e != null && e.SocketError == SocketError.Success)
            {
                var s = e.AcceptSocket;
                if (s.Connected)
                {
                    try
                    {
                        Interlocked.Increment(ref m_connected);
                        var c = m_avaliable.Pop();
                        c.SetSocket(s);
                        c.ConnectedTime = DateTime.Now;
                        c.ReadEventArgs.UserToken = c;

                        OnNewConnection?.Invoke(c.ReadEventArgs);
                    }
                    catch
                    {
                        e.AcceptSocket = null;
                    }

                }
            }
            StartAccept(e);
        }
#region Close
        void CloseConnection(Connection c)
        {
            lock (m_Pool)
            {
                if (c != null)
                {
                    c.Close();
                    m_avaliable.Push(c);
                }
                c.ReadEventArgs.Completed -= IOCPCompleted;
                OnConnectionClose?.Invoke(c);
                Interlocked.Decrement(ref m_connected);
                m_operate.Release();
            }
        }
#endregion
#endregion

#region Receive

        protected void ProcessReceive(SocketAsyncEventArgs e)
        {
            if (e != null && e.SocketError == SocketError.Success && e.BytesTransferred > 0)
            {
                var s = e.UserToken as Connection;
                if (s.Connect.Connected)
                {
                    var data = new byte[e.BytesTransferred];
                    Array.Copy(e.Buffer, e.Offset, data, 0, data.Length);
                    try
                    {
                        if (!s.Connect.ReceiveAsync(e))
                        {
                            ProcessReceive(e);
                        }
                        s.Buffer.Enqueue(data);//如果有就添加到队列
                    }
                    catch (Exception ex)
                    {
                        OnNewExceptionRaised?.Invoke(ex);
                    }
                }
                else
                {
                    CloseConnection(s);
                }
            }
            else if (e.SocketError != SocketError.Success)
            {
                CloseConnection(e.UserToken as Connection);
            }
        }

#endregion

#region Disconnect 
        public void Disconnect(Connection e)
        {
            CloseConnection(e);
        }

        public void Disconnect(string uid)
        {
            Disconnect(m_Pool[uid]);
        }

#endregion


#region IOCP
        void ClientRequest(SocketAsyncEventArgs e, CloudReader.Net.Protocol.CloudReaderPackage data)
        {
            OnNewPackageReceive?.Invoke(e, data);
        }
        public void IOCPCompleted(object sender, SocketAsyncEventArgs e)
        {
            var c = e.UserToken as Connection;
            c.ActiveTime = DateTime.Now;

            switch (e.LastOperation)
            {
                case SocketAsyncOperation.Receive:
                    {
                        ProcessReceive(e);
                        break;
                    }
                case SocketAsyncOperation.Disconnect:
                    Disconnect(e.UserToken as Connection);
                    break;
            }
        }


#endregion



    }
}
